import java.awt.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.geom.Rectangle2D;

import javax.swing.*;

/**
* @file JShaftPanel.java
*
* @brief Diese Datei enthält die JShaftPanel-Klasse.
*
* @author Alrik Künne
*
* @date 01.06.2012 - erste Version
* @date 19.06.2012 - einige Veränderungen, Multi-Threading
**/


/** 
* @class JShaftPanel 
* 
* @brief Das Panel, auf dem der Fahrstuhlschacht gezeichnet wird
* 
* Abgeleitet von JPanel, es wurde die Paint Methode überschrieben.
*/ 
@SuppressWarnings("serial")
public class JShaftPanel extends JPanel {
	private int doorcond, floordoor, liftpos, personenanz;
	Image offscreenImage;
	Graphics offscreenGraphics;
	Image images[], currentimage;
	
	/**
	 * @brief Der Konstruktor
	 *
	 * initialisiert das Panel und initialisiert die die Kabine in der untersten Etage mit geschlossenen Türen
	 */
	public JShaftPanel(){
		super();
		personenanz=0;
		drawDoors(0,1);
		images = new Image[15];
		for(int i=0; i<15;i++){
			
			images[i] = Toolkit.getDefaultToolkit().getImage(getClass().getResource("images/"+Integer.toString(i)+".jpg"));
			
			//images[i] = new ImageIcon("images/"+Integer.toString(i)+".jpg").getImage();
		}
		
		addComponentListener(new ComponentListener() 
		  {  
		          public void componentResized(ComponentEvent evt) {
		        	  changePicture();
		          }

				@Override
				public void componentHidden(ComponentEvent arg0) {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void componentMoved(ComponentEvent arg0) {
					// TODO Auto-generated method stub
					
				}

				@Override
				public void componentShown(ComponentEvent arg0) {
					// TODO Auto-generated method stub
					
				}
		  });
		
	}
	
	/**
	 * @brief wechselt das Bild (image) auf das Benötigte aus und skaliert es bei bedarf
	 * 
	 * Wenn die Größe der Komponente verändert wird, so wird das Bild auch neu skaliert und wieder ausgewechselt
	 *
	 */
	private synchronized void changePicture(){
		int index;
		if (personenanz>13){
			index=14;
		}else{
			index=personenanz;
		}
		currentimage = images[index].getScaledInstance(
  		    	-1,
  		    	getSize().height/9,
  		    	Image.SCALE_SMOOTH );
		if((int)(243.0/342.7*(float)(getSize().height/9))>80){
			
			currentimage = images[index].getScaledInstance(
				80,
		    	-1,
		    	Image.SCALE_SMOOTH );
			System.out.println("HALLLOOOO");
		}
	}
	
	/**
	 * @brief Zeichnet die Tür in einer bestimmten Etage mit einem Bestimmten Grad an "Öffnung"
	 *
	 * @param cond - der Zustand der Türen (0-40)
	 * @param floor - die Etage auf der die Tür gezeichnet werden soll
	 * 
	 * die Cond 0(zu)-40(sperrangelweitoffen) gibt an wie weit die Tür offen steht, der floor, welche Etage
	 */
	public void drawDoors(int cond, int floor){
		floordoor=floor;
		doorcond=cond;
		repaint();
	}
	
	/**
	 * @brief Zeichnet den Lift in einer Bestimmten Etage mit einem Versatz.
	 *
	 * @param pos - der Versatz der Kabine zur Etage (0-40)
	 * @param floor - die Etage auf der die Kabine gezeichnet werden soll
	 * 
	 * in der richtigen Reihenfolge vom Dispatch-Thread aufgerufen, bewegt sich die Kabine ruckelfrei durch den Schacht
	 */	
	public void drawLift(int pos, int floor){
		floordoor=floor;
		liftpos=pos;
		repaint();
	}
	
	/**
	 * @brief Über diese Methode wird die Zahl der Personen festgelegt, die im Fahrstuhl dargestellt werden.
	 *
	 * @param Personen eine Zahl zwischen 0-14
	 */
	public void setPersonen(int Personen){
		if(Personen!=personenanz){
			personenanz=Personen;
			changePicture();
		}
	}
	
	/**
	 * @brief Zeichnet die gesamte Grafik im Hintergrund (für double-Buffering)
	 *
	 * Diese Funktion wertet aus, wo die Kabine sich befindet und stellt das im Schacht dar, außerdem wird hier dargestellt, ob, wo und wie die Türen gezeichnet werden sollen und führt das korrekt aus.<br/>
	 * Die Methode wird aufgerufen, wenn eine Neuzeichnung notwendig ist, z.b. wenn sich die Fenstergröße ändert oder der Fahrstuhl bzw. die Türen sich bewegt haben.
	 * Diese Methode wertet außerdem aus, wieviel Platz verwendet werden kann und nutzt diesen. 
	 * Die Darstellung erfolgt hier noch nicht, es wird nur alles vorbereitet.
	 * Infos Zum double-Buffering
	 * <a href"http://openbook.galileodesign.de/javainsel5/javainsel14_008.htm#Rxx747java14008040004CF1F0221F7">http://openbook.galileodesign.de/javainsel5/javainsel14_008.htm#Rxx747java14008040004CF1F0221F7</a>
	 *  Auf dem Entwicklungsmac ist das Doublebuffering nicht notwendig, unter einigen Linux-Distributionen ist ein starkes Flackern aufgetreten, meist in Kombination mit der openJRE.
	 */
	private synchronized void offPaint(){
		
	    Dimension d = getSize();

	    
		offscreenImage    = createImage(d.width, d.height);
		offscreenGraphics = offscreenImage.getGraphics();

		
		Graphics2D g2 = (Graphics2D) offscreenGraphics; //Aliasing
	    int heightoflevel=d.height/9;
	    //Stockwerke
	    for(int i=0;i<9; i++)
	    {
	    	if(i%2!=0){
	    		g2.setPaint(Color.lightGray);
	        	
	        }else{
	        	g2.setPaint(Color.white);
	        }
	    	g2.fill(new Rectangle2D.Double(0, i*heightoflevel, 200, heightoflevel));
        	g2.setPaint(Color.black);
	    }
	    //Liftkabine
	    if(doorcond!=0 && currentimage!=null ){
		    g2.setPaint(Color.white); //Innenfarbe der Kabine
		    g2.fill(new Rectangle2D.Double(100-doorcond, (9-floordoor)*heightoflevel, 2*doorcond, heightoflevel)); //Der Seitenrand beim Bild
		    g2.drawImage(currentimage, 100-currentimage.getWidth(null)/2, (9-floordoor)*heightoflevel+((heightoflevel-currentimage.getHeight(null))/2), null);//Das Bild
	    }
	    g2.setPaint(Color.gray);
	    if(doorcond!=0){
	    	g2.fill(new Rectangle2D.Double(60, (9-floordoor)*heightoflevel-(int)((float)heightoflevel*((float)liftpos/40.0)), 40-doorcond, heightoflevel)); //Linke Tür
	    	g2.fill(new Rectangle2D.Double(100+doorcond, (9-floordoor)*heightoflevel-(int)((float)heightoflevel*((float)liftpos/40.0)), 40-doorcond, heightoflevel)); //Rechte Tür
	    }else
	    	g2.fill(new Rectangle2D.Double(60, (9-floordoor)*heightoflevel-(int)((float)heightoflevel*((float)liftpos/40.0)), 80, heightoflevel)); //Kabine
	    g2.setPaint(Color.black);
	    
	   
	    
	    //Etage
	    for(int i = 0;i<9; i++)
	    {        	
	    	g2.drawRect(60, i*heightoflevel, 80, heightoflevel);
	        if((i!=(9-floordoor)) || (doorcond==0))
	            	g2.drawString(Integer.toString(9-i)+".Etage", 75 , i*heightoflevel+20);
	    }				
	}
	
	
	
	/**
	 * @brief Zeichnet den gesamten Schacht in das Panel.
	 *
	 * @param g - Die Unterlage auf der gezeichnet wird. 
	 * 
	 * Die Funktion, die für das Zeichnen zuständig ist. da wir double-Buffering verwenden, wird hier nur die fertige Zeichnung geladen. 
	 */
	@Override 
	public void paintComponent(Graphics g) {
		offPaint();	//errechnet das, was dargestellt werden soll
		super.paintComponent(g);    // paints background  
		if ( offscreenImage != null ){
			g.drawImage( offscreenImage, 0, 0, this );
			offscreenImage=null;
		}else
			System.err.println("kein double-Buffering möglich=(");
    }
}
